/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
 * lockfs.h
 *
 * Userspace dlm defines
 *
 * Copyright (C) 2002, 2004 Oracle.  All rights reserved.
 */

#ifndef LOCKFS_H
#define LOCKFS_H

#include "ocfs2.h"
#include "lockglue.h"

/* user_lock_res->l_flags flags. */
#define USER_LOCK_ATTACHED      (0x00000001) /* we have initialized
					       * the lvb */
#define USER_LOCK_BUSY          (0x00000002) /* we are currently in
					       * dlm_lock */
#define USER_LOCK_BLOCKED       (0x00000004) /* blocked waiting to
					      * downconvert*/
#define USER_LOCK_IN_TEARDOWN   (0x00000008) /* we're currently
					      * destroying this
					      * lock. */
#define USER_LOCK_QUEUED        (0x00000010) /* lock is on the
					      * workqueue */
#define USER_LOCK_IN_CANCEL     (0x00000020)

#define USER_LOCK_UNLOCKING		(0x00004000)

struct user_lock_res {
	spinlock_t               l_lock;

	int                      l_flags;

#define USER_LOCK_ID_MAX_LEN  32
	char                     l_name[USER_LOCK_ID_MAX_LEN];
	int                      l_namelen;
	int                      l_level;
	unsigned int             l_ro_holders;
	unsigned int             l_ex_holders;

	int                      l_requested;
	int                      l_blocking;

	wait_queue_head_t        l_event;

	/* used for DLM */
	struct ocfs2_dlm_lksb    l_lksb;
	struct work_struct       l_work;

	/* used for ADL */
	u64						 l_blkno; /* disk lock block no */
	int						 l_sector_offset;
	struct adl_lockstatus	 l_adllksb;
};

struct lockfs_inode_private {
	void *ip_conn;

	struct user_lock_res  ip_lockres; /* unused for directories. */
	struct inode          *ip_parent;

	struct inode          ip_vfs_inode;
	enum ocfs2_lock_class ip_lock_stack;
};

static inline struct lockfs_inode_private *
LOCKFS_I(struct inode *inode)
{
	return container_of(inode,
			struct lockfs_inode_private,
			ip_vfs_inode);
}

struct lockfs_filp_private {
	int                  fp_lock_level;
};

#define LOCKFS_MAGIC	0x76a9f425

static inline void *
cluster_connection_from_user_lockres(struct user_lock_res *lockres)
{
	struct lockfs_inode_private *ip;

	ip = container_of(lockres,
			  struct lockfs_inode_private,
			  ip_lockres);
	return ip->ip_conn;
}

static inline void lockfs_inc_holders(struct user_lock_res *lockres, int level)
{
	switch (level) {
	case OCFS2_LOCK_EX:
		lockres->l_ex_holders++;
		break;
	case OCFS2_LOCK_PR:
		lockres->l_ro_holders++;
		break;
	default:
		BUG();
	}
}

static inline void lockfs_dec_holders(struct user_lock_res *lockres, int level)
{
	switch (level) {
	case OCFS2_LOCK_EX:
		BUG_ON(!lockres->l_ex_holders);
		lockres->l_ex_holders--;
		break;
	case OCFS2_LOCK_PR:
		BUG_ON(!lockres->l_ro_holders);
		lockres->l_ro_holders--;
		break;
	default:
		BUG();
	}
}

static inline int __check_wait_flag(struct user_lock_res *lockres, int flag)
{
	int ret;

	spin_lock(&lockres->l_lock);
	ret = lockres->l_flags & flag;
	spin_unlock(&lockres->l_lock);

	return ret;
}

static inline void lockfs_wait_on_flag(struct user_lock_res *lockres, int flag)
{
	wait_event(lockres->l_event,
		   !__check_wait_flag(lockres, flag));
}

static inline void lockfs_recover_from_error(struct user_lock_res *lockres)
{
	spin_lock(&lockres->l_lock);
	lockres->l_flags &= ~USER_LOCK_BUSY;
	spin_unlock(&lockres->l_lock);
	wake_up(&lockres->l_event);
}

#endif
